package ar.edu.itba.pod.Legajo47342.simulation;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Maps;

import ar.edu.itba.pod.Legajo47342.Node;
import ar.edu.itba.pod.simul.communication.NodeAgentLoad;
import ar.edu.itba.pod.simul.simulation.Agent;
import ar.edu.itba.pod.simul.simulation.Simulation;
import ar.edu.itba.pod.simul.simulation.SimulationInspector;
import ar.edu.itba.pod.simul.simulation.SimulationManager;

public class SimulationManagerImpl implements SimulationManager {
	private Node node;
	private List<Agent> agents;
	private boolean running;
	Simulation simul;
	private final Map<Class<?>, Object> enviroment;

	public SimulationManagerImpl(Node node) {
		super();
		this.node = node;
		this.running = false;
		this.agents = new ArrayList<Agent>();
		this.simul = new SimulationImpl(this);
		this.enviroment = Maps.newHashMap();
	}

	@Override
	public void start() {
		for (Agent a : agents) {
			try {
				a.start();
			} catch (IllegalThreadStateException e) {
				System.out.println("Agent already started");
			}
		}
		running = true;

	}

	@Override
	public void shutdown() {
		for (Agent a : agents) {
			a.finish();
		}
		
		for (Agent a : agents) {
			try {
				a.join();
			} catch (InterruptedException e) {
				System.out.println("Inerrupted while finishing agents");
			}
		}
		
		running = false;

	}

	@Override
	public void addAgent(Agent agent) {
		
		try {
			NodeAgentLoad load = node.getManager().getSimulationCommunication().getMinimumNodeKnownLoad();
			System.out.println("Lo agrego en: "+load.getNodeId());
			node.getManager().getConnectionManager(load.getNodeId()).getSimulationCommunication().startAgent(agent.getAgentDescriptor());
		} catch (RemoteException e) {
			e.printStackTrace();
		}
			
}
	
	public void storeAgent(Agent agent){
		synchronized (agents) {
			agents.add(agent);
		}
	}

	@Override
	public void removeAgent(Agent agent) {
		synchronized (agents) {
			agents.remove(agent);
		}

	}

	@Override
	public Simulation simulation() {
		return simul;
	}

	@Override
	public SimulationInspector inspector() {
		return (SimulationImpl)simul;
	}

	@Override
	public <T> void register(Class<T> type, T instance) {
		enviroment.put(type, instance);

	}

	@Override
	public Collection<Agent> getAgents() {
		return agents;
	}
	
	public Map<Class<?>, Object> getEnviroment() {
		return enviroment;
	}

}
